package com.bwie.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.domain.Menu;
import com.bwie.common.domain.User;
import com.bwie.common.domain.request.UserReq;
import com.bwie.common.domain.response.UserResp;
import com.bwie.common.exceptions.BizExceptions;
import com.bwie.common.result.Result;
import com.bwie.common.utils.JwtUtils;
import com.bwie.common.utils.StringUtils;
import com.bwie.exception.LoginException;
import com.bwie.remote.RemoteService;
import com.bwie.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;

import java.util.concurrent.TimeUnit;

/**
 * @className: UserServiceImpl
 * @Description: TODO
 * @version: v1.８.0
 * @author: GONGWENXUE
 * @date: 2025/10/22 9:29
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    RemoteService remoteService;
    @Autowired
    HttpServletRequest request;
    @Autowired
    RedisTemplate redisTemplate;
    @Override
    public UserResp userLogin(UserReq userReq) {
        String username = userReq.getUsername();//用户名
        String password = userReq.getPassword();//密码
        final String LOCKED_NUM_KEY = "login:fail:count"+ password;//按密码记录失败次数
        final int MAX_SESSION_COUNT = 3;//最大重试次数
        final int TIME = 5 * 60;//时间
        //判断时间内到达最大尝试数
        Integer failCount = (Integer) redisTemplate.opsForValue().get(LOCKED_NUM_KEY);
        if(failCount!=null && failCount>=MAX_SESSION_COUNT){
            throw new RuntimeException("达到最大尝试次数");
        }
        HttpSession session = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession();
        Integer sessionAttribute = (Integer) session.getAttribute("SESSION_RETRY_COUNT" + password);
        if(sessionAttribute==null){
            sessionAttribute=0;
        }

        //非空验证
        if(StringUtils.isBlank(username)){
            throw new RuntimeException("手机号不可为空");
        }
        if(StringUtils.isBlank(password)){
            throw new RuntimeException("验证码不可为空");
        }
        if(!password.equals(userReq.getPassword())){
            throw new RuntimeException("验证码不一致");
        }
        Result<User> byUsers = remoteService.selectNameByUser(username);
        User sysUsers = byUsers.getData();
        if(sysUsers==null){
            throw new RuntimeException("不可为空");
        }
        //检查单次会话重试次数
        if(sessionAttribute>=MAX_SESSION_COUNT){
            //到达最大重试次数,跟新全局并提示
            updateLoginFailCount(LOCKED_NUM_KEY,failCount);
            session.setAttribute("SESSION_RETRY_COUNT" +password,sessionAttribute);//清除会话技术
            throw new RuntimeException("密码连错三次，请重新尝试");
        }
        //登录成功 清除失败次数
        redisTemplate.delete(LOCKED_NUM_KEY);
        request.removeAttribute("SESSION_RETRY_COUNT"+password);
        //生成token
        Map<String, Object> claims=new HashMap<>();
        UUID sysKey = UUID.randomUUID();
        claims.put(TokenConstants.TOKEN,sysKey);
        //把jwt生成token
        String token = JwtUtils.createToken(claims);
        //存入redis
        redisTemplate.opsForValue().set(JwtConstants.USER_KEY+sysKey,sysUsers,10, TimeUnit.MINUTES);
        //响应前端
        UserResp userResp = new UserResp();
        userResp.setToken(token);
        userResp.setTime("10ITM");
        return userResp;
    }
    //记录失败次数
    private void updateLoginFailCount(String lockedNumKey, Integer failCount) {
        if(failCount==null){
            redisTemplate.opsForValue().set(lockedNumKey,1,5,TimeUnit.MINUTES);
        }else {
            redisTemplate.opsForValue().increment(lockedNumKey); //增加失败次数
            redisTemplate.expire(lockedNumKey,1,TimeUnit.MINUTES);//重置过期时间
        }
    }
    @Override
    public UserResp userPhone(UserReq userReq) {
        String phone = userReq.getPhone();//手机号
        String code = userReq.getCode();//验证码
        //非空验证
        if(StringUtils.isBlank(phone)){
            throw new RuntimeException("手机号不可为空");
        }
        if(StringUtils.isBlank(code)){
            throw new RuntimeException("验证码不可为空");
        }
        //手机号格式验证
        if(!phone.matches("1[3-9]\\d{9}")){
            throw new RuntimeException("手机号格式错误");
        }
        Result<User> byUser = remoteService.selectPhoneByUser(phone);
        User sysUser = byUser.getData();
        if(sysUser==null){
            throw new RuntimeException("不可为空");
        }
        //生成token
        Map<String, Object> claims=new HashMap<>();
        UUID sysKey = UUID.randomUUID();
        claims.put(TokenConstants.TOKEN,sysKey);
        //把jwt生成token
        String token = JwtUtils.createToken(claims);
        //存入redis
        redisTemplate.opsForValue().set(JwtConstants.USER_KEY+sysKey,sysUser,10, TimeUnit.MINUTES);
        //响应前端
        UserResp userResp = new UserResp();
        userResp.setToken(token);
        userResp.setTime("10ITM");
        return userResp;
    }

    @Override
    public void getCode(String phone) {
        //手机号
        Result<User> result = remoteService.selectPhoneByUser(phone);
        User user = result.getData();
        if(user==null){
            throw new RuntimeException("不可为空");
        }
        //非空判断
        if(StringUtils.isBlank(phone)){
            throw new RuntimeException("手机号不可为空");
        }
        //验证
        if(!phone.matches("1[3-9]\\d{9}")){
            throw new RuntimeException("手机号有误");
        }
        //生成手机号
        String code = String.valueOf(RandomUtil.randomInt(1000, 9999));
        //存入redis
        redisTemplate.opsForValue().set(JwtConstants.USER_KEY+phone,code,1,TimeUnit.MINUTES);
    }

    @Override
    public List<Menu> getMenu() {
        String token = request.getHeader(TokenConstants.TOKEN);
        String userKey = JwtUtils.getUserKey(token);
        User user = (User) redisTemplate.opsForValue().get(TokenConstants.LOGIN_TOKEN_KEY + userKey);
        Integer userId = user.getUserId();
        Result<List<Menu>> ridByMenu = remoteService.getMenu(userId);
        List<Menu> menuData = ridByMenu.getData();
        if(ridByMenu.getCode()!=200){
            throw new BizExceptions("异常");
        }
        if(menuData==null){
            throw new BizExceptions("不可为空");
        }
        return getNode(menuData,0);
    }

    private List<Menu> getNode(List<Menu> menuData, int i) {
        ArrayList<Menu> list = new ArrayList<>();
        for (Menu menuDatum : menuData) {
            if(menuDatum.getPid().equals(i)){
                List<Menu> menus=getNode(menuData,menuDatum.getMenuId());
                menuDatum.setChildren(menus);
                list.add(menuDatum);
            }
        }
        return list;
    }
}
